#include <Ogre.h>
//#include <SDL.h>
#include <stdio.h>
#include "EApp.h"
#include "EGame.h"
#include "ECharacter.h"
#include "EScreen.h"
#include "ESceneManager.h"
#include "EPhScene.h"
#include "EPhActor.h"
#include "EShape.h"
#include "EPhysics.h"
#include "ePhCollisionsGroups.h"
#include "EEventShape.h"
#include "eCPP.h"

namespace engine {

class ETestEventShape : EEventShape
{
public:
  ETestEventShape(const EVector& vDimensions) :
  EEventShape(EBoxShape(vDimensions), EEventShape::SHAPE_EVENT_ALL )
  {

  }
  void onEnter            ( EEntity& entity, void *pUserData ) const 
  {
    int i=3;
  };
  void onIsStillInside    ( EEntity& entity, void *pUserData ) const 
  {
    int i=3;
  };
  void onLeave            ( EEntity& entity, void *pUserData ) const 
  {
    int i=3;
  };
};

class SampleApp : public EApp
{
  EScene*     m_pScene;
  EScreen     *m_pScreen;
  ECharacter  *m_pCharacter;
  Plane*      m_pGround;
  EPhScene*   m_pPhScene;
  EPhActor*   m_pPhActor;
  EPhMaterial  *m_pMaterial;
  EBoxShape     m_BoxShape;
  ESphereShape  m_SphereShape;
  ECapsuleShape m_CapsuleShape;
  ETestEventShape m_TestEventShape;
public:
  // Basic constructor
  SampleApp() :
  m_pScreen( NULL ),
  m_pCharacter( NULL ),
  m_BoxShape( EVector(150.f, 150.f, 150.f) ),
  m_SphereShape( 100.f ),
  m_CapsuleShape( 30.f, 150.f),
  m_TestEventShape( EVector( 30.f ) )
  {
    g_pGame = new EGame();
  }

  ~SampleApp()
  {
    g_pGame->endGame();
    delete m_pGround;
    delete g_pPhysics;
    delete g_pGame; g_pGame = NULL;
  }

protected:

  // Just override the mandatory create scene method
  bool createScene(void)
  {
    g_pPhysics = new EPhysics();
    // Create a light
    Light* pLight = m_pSceneManager->createLight("Light0");
    pLight->setType(Light::LT_DIRECTIONAL);
    pLight->setDirection( Vector3(-1.f, 1.f, 0.f) );
    pLight->setDiffuseColour(1.f, 1.f, 0.5f);
    pLight->setSpecularColour(1.f, 1.f, 1.f);
    pLight->setCastShadows( true );

    pLight = m_pSceneManager->createLight("Light1");
    pLight->setType( Light::LT_DIRECTIONAL );
    pLight->setDirection( Vector3(1.f, 1.f, 0.f) );
    pLight->setDiffuseColour(0.6f, 0.6f, 1.f);
    pLight->setSpecularColour(1.f, 1.f, 1.f);
    pLight->setCastShadows( true );

    m_pSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(pLight );

    // Scene
    ESceneDesc    sceneDesc;
    m_pScene = g_pGame->createScene("mainScene", sceneDesc);
    cASSERT( m_pScene != NULL );
    g_pGame->setCurrentScene( "mainScene" );

    // Screen
    EScreenDesc   screenDesc;
    screenDesc.m_sBagroundFileName = "seabridge.jpg";
    m_pScreen = m_pScene->createScreen("seabridge", screenDesc );
    m_pScreen->load();
    m_pScene->setCurrentScreen( "seabridge" );
    
    // Ground
    m_pGround = new Plane(Vector3::UNIT_Y, Vector3::ZERO);
    MeshManager::getSingleton().createPlane("floor",
      ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, *m_pGround,
      2000, 2000, 10, 10, true, 1, 200, 200, Vector3::UNIT_Z);
    Entity* pGroundEntity = m_pSceneManager->createEntity("plane", "floor");
    pGroundEntity->setMaterialName("debug/Grid");
    pGroundEntity->setCastShadows(false);
    m_pSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(pGroundEntity);

    ECharacterDesc characterDesc;
    characterDesc.m_sModelFileName = "ninja.mesh" ;
    m_pCharacter = m_pScene->createCharacter( "player", characterDesc );
    cTEST( m_pCharacter->load( *m_pSceneManager ) );
    cTEST( m_pCharacter->setAnimationState( "Idle2" ) );
    m_pCharacter->enableAnimation( true );
    /// todo not working
    m_pCharacter->setScale( 0.2f );
    g_pGame->setPlayerCharacter( m_pCharacter );

    m_pScene->addEventShape( m_TestEventShape );

    /*characterDesc.m_sModelFileName = "jaiqua.mesh" ;
    m_pCharacter = m_pScene->createCharacter( "jaiqua", characterDesc );
    cTEST( m_pCharacter->load( *m_pSceneManager ) );
    cTEST( m_pCharacter->setAnimationState( "Walk" ) );
    m_pCharacter->enableAnimation( true );*/
    /// todo not working
    //m_pCharacter->setScale( 0.2f );

    /*characterDesc.m_sModelFileName = "spider.mesh" ;
    m_pCharacter = m_pScene->createCharacter( "spider", characterDesc );
    cTEST( m_pCharacter->load( *m_pSceneManager ) );
    cTEST( m_pCharacter->setAnimationState( "walk" ) );
    m_pCharacter->enableAnimation( true );
    /// todo not working
    m_pCharacter->setScale( 1.f );*/

    cTEST( g_pGame->m_sceneManager.setCurrentScene( "mainScene" ) );

    EStaticColliderDesc colDesc;
    colDesc.m_sModelFileName = "seabridge_col.mesh";
    EStaticCollider* pCol = m_pScene->createStaticCollider( colDesc );
    cTEST( pCol->load( *m_pSceneManager ) );
    pCol->setScale( 100.f );

    /*// Create background material
    // Example of background scrolling
    //material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setScrollAnimation(-0.25, 0.0);

    */
    g_pGame->startGame();

    EPhScene* pPhScene = m_pScene->getPhScenePtr();
    cASSERT( pPhScene != NULL );
    EPhActorDesc colActorDesc;
    ETriangleMeshShape colTriangleMeshShape( pCol->getOgreMesh() );
    /*EPhTriangleMeshShapeDesc colTriangleMeshDesc( pCol->getOgreMesh() );
    colTriangleMeshDesc.m_vScale = pCol->getScale();*/

    //EBoxShape   boxShape(EVector(10.f, 10.f, 10.f));
    //colActorDesc.addBoxShape( boxShape, COLLISION_GROUP_CHARACTER_COLLIDE );
    EPhShapeDesc colPhShapeDesc( colTriangleMeshShape );
    colPhShapeDesc.m_eCollisionGroup = COLLISION_GROUP_CHARACTER_COLLIDE;
    colActorDesc.addShape( colPhShapeDesc );
    EPhActor* pBoxActor = pPhScene->createActor( colActorDesc );
    //pBoxActor->setPosition( EVector(0.f, 0.f, -60.f) );

    /*EPhMaterialDesc matDesc;
    m_pMaterial = m_pPhScene->createMaterial( matDesc );

    EPlaneShape shape(EVector::UNIT_Y, 0.f);
    actorDesc.addPlaneShape( shape, m_pMaterial );
    m_pPhActor = m_pPhScene->createActor( actorDesc );*/

    g_debugRenderer.startDebug();

    return true;
  }
};

} // end namespace

using namespace engine;

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
#ifdef _MSC_VER // Visual studio
  // Memory leaks report
  _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    /*if((SDL_Init(SDL_INIT_JOYSTICK)==-1)) { 
      printf("Could not initialize SDL: %s.\n", SDL_GetError());
      exit(-1);
    }*/

    // Create application object
    
    try
    {
      SampleApp app;
      if( !app.go() )
      {
        // TODO
      }
    }
    catch( Exception& e )
    {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else

        std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
    }

    //SDL_Quit();

    return 0;
}


